package mazegame;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Container;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import javax.swing.ScrollPaneConstants;

import mazegame.MazeClient.ClientStatus;

@SuppressWarnings("serial")
public class ClientUI extends JFrame {

	public static void main(String[] args) {
		ClientUI clientUI = new ClientUI();
		clientUI.displayClientUI();
	}

	private JLabel lblServerName = new JLabel("Hostname");
	private JTextField txtHostIPAddr = new JTextField(10);
	private JLabel lblServerPort = new JLabel("Port");
	private JTextField txtServerPort = new JTextField(10);
	private JButton btnJoinGame = new JButton("Join Game");
	private JButton btnLeaveGame = new JButton("Leave Game");
	private JTextArea areaViewLogs = new JTextArea(20, 30);
	private JTextArea areaMazeMap = new JTextArea(10, 20);
	MazeClient mazeClient = null;

	private ClientUpdateTimer clientUpdateTimer;

	public ClientUI() {
		super("Distributed Maze Game");// Title
		mazeClient = new MazeClient();// Initializing Client
		txtHostIPAddr.setText("172.28.177.113");
		txtServerPort.setText("2001");

		btnLeaveGame.setEnabled(false);// Disable Leave Game Button

		// Add Action Listeners
		btnJoinGame.addActionListener(new ClientBtnListener());
		btnLeaveGame.addActionListener(new ClientBtnListener());
		areaMazeMap.addKeyListener(new ClientKeyListener());

	}

	public void displayClientUI() {
		areaViewLogs.setEditable(false);
		areaMazeMap.setEditable(false);
		Container content = getContentPane();
		content.setBackground(Color.lightGray);
		
		JScrollPane scrollAreaViewLog = new JScrollPane(areaViewLogs); 
		scrollAreaViewLog.setBounds(10,60,780,100);
		scrollAreaViewLog.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS);

		// Game option panel
		JPanel panelGameOptions = new JPanel();
		panelGameOptions.setBorder(BorderFactory
				.createTitledBorder("Game Options"));
		panelGameOptions.add(lblServerName);
		panelGameOptions.add(txtHostIPAddr);
		panelGameOptions.add(lblServerPort);
		panelGameOptions.add(txtServerPort);
		panelGameOptions.add(btnJoinGame);
		panelGameOptions.add(btnLeaveGame);

		// View Logs Panel
		JPanel panelViewLog = new JPanel();
		panelViewLog.setBorder(BorderFactory.createTitledBorder("Logs"));
		panelViewLog.add(scrollAreaViewLog);

		// Maze Game Panel
		JPanel panelMazeMap = new JPanel();
		panelMazeMap.setBorder(BorderFactory.createTitledBorder("Maze Map"));
		panelMazeMap.add(areaMazeMap);

		JPanel bottomPanel = new JPanel();
		bottomPanel.setLayout(new FlowLayout());
		bottomPanel.add(panelMazeMap);
		bottomPanel.add(panelViewLog);

		content.add(panelGameOptions, BorderLayout.CENTER);
		content.add(bottomPanel, BorderLayout.SOUTH);

		pack();
		setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
		setVisible(true);

	}

	private class ClientBtnListener implements ActionListener {
		public void actionPerformed(ActionEvent e) {

			if (e.getSource() == btnJoinGame) {// If Join Game is Clicked

				setLogs("Join Game Button Clicked. Calling for RMI...", false);

				if (!mazeClient.isGameJoined()) // Check Client already Joined
												// the game
				{
					// Initialize RMI
					try {
						String host = txtHostIPAddr.getText();
						int port = Integer.parseInt(txtServerPort.getText());
						String startRMIResult = mazeClient
								.initiateRemoteMazeServer(host, port);
						setLogs(startRMIResult, false);
					} catch (Exception e1) {
						setLogs("ERROR: RMI registry initializing failed.",
								false);
						e1.printStackTrace();
						return;
					}

					// Initialize Client
					try {
						mazeClient.updateJoiningClient();
					} catch (Exception e1) {
						setLogs("ERROR: Set up client failed", false);
						e1.printStackTrace();
						return;
					}

					// start the update timer
					clientUpdateTimer = new ClientUpdateTimer(1000 ,
							ClientUI.this);

					// Enable Leave Game button and Disable Join Game
					btnJoinGame.setEnabled(false);
					btnLeaveGame.setEnabled(true);
					// Request focus set to Maze map text area
					areaMazeMap.requestFocusInWindow();

				} else {
					setLogs("Player already Joined..", false);
				}

			} else if (e.getSource() == btnLeaveGame) {

				setLogs("Leave Game Button Clicked. Calling for RMI...", false);

				if (mazeClient.isGameJoined()) // Check client already joined to
												// the game
				{

					// Update Leaving Client
					try {
						mazeClient.updateLeavingClient();
					} catch (Exception e1) {
						setLogs("ERROR: Update leaving client failed", false);
						e1.printStackTrace();
						return;
					}

					// // stop the update timer
					// timer.timer.cancel();
					//
					// Disable Leave Game button and Enable Join Game
					btnJoinGame.setEnabled(true);
					btnLeaveGame.setEnabled(false);

				} else {
					setLogs("Player already leaved..", false);
				}

			}

		}
	}

	private class ClientKeyListener implements KeyListener {
		public void keyPressed(KeyEvent e) {

			int keyCode = e.getKeyCode();
			setLogs("Player request to move......", false);
			String playerMoveStatus = "";
			String currentMazeMap = "";
			switch (keyCode) {
			case KeyEvent.VK_UP: {

				playerMoveStatus = mazeClient
						.playerMoveStatus(Constants.Direction.DIR_UP);
				break;
			}
			case KeyEvent.VK_DOWN: {
				playerMoveStatus = mazeClient
						.playerMoveStatus(Constants.Direction.DIR_DOWN);
				break;
			}
			case KeyEvent.VK_LEFT: {
				playerMoveStatus = mazeClient
						.playerMoveStatus(Constants.Direction.DIR_LEFT);
				break;
			}
			case KeyEvent.VK_RIGHT: {
				playerMoveStatus = mazeClient
						.playerMoveStatus(Constants.Direction.DIR_RIGHT);
				break;
			}
			}
			currentMazeMap = mazeClient.updateMazeMap();
			setLogs(playerMoveStatus, false);
			setMazeMap(currentMazeMap);

		}

		@Override
		public void keyTyped(KeyEvent e) {
			// Not Implemented

		}

		@Override
		public void keyReleased(KeyEvent e) {
			// Not Implemented

		}

	}

	public void setLogs(String logInfo, boolean clearOldLogs) {

		areaViewLogs.setText(MazeUtil.log(logInfo, areaViewLogs.getText()));

	}

	public void setMazeMap(String mazeMapPlot) {
		areaMazeMap.setText(mazeMapPlot);
	}

	public void requestUpdate() {

		String currentMazeMap = "";
		String playerMoveStatus = mazeClient.playerMoveStatus(null);
		
		if (mazeClient.getStatus().equals(ClientStatus.CLIENT_GAME_STARTING)) {
			setLogs(playerMoveStatus,false);
		}

		if (mazeClient.getStatus().equals(ClientStatus.CLIENT_GAME_RUNNING)) {
			currentMazeMap = mazeClient.updateMazeMap();
			// setLogs(playerMoveStatus, false)
			setMazeMap(currentMazeMap);
			clientUpdateTimer.timer.cancel();
			
		}
	}
}
